Skip to content

feat(base44-sandbox): add cloud-sandbox remote-dev skill flavor - #121

Merged
carmelc merged 15 commits into
mainfrom
feat/base44-sandbox-flavor
Jun 30, 2026
Merged

feat(base44-sandbox): add cloud-sandbox remote-dev skill flavor#121
carmelc merged 15 commits into
mainfrom
feat/base44-sandbox-flavor

Conversation

@carmelc

@carmelc carmelc commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What

Adds a focused, separately-installable sandbox flavor for developing a Base44 app inside Base44's cloud sandbox (the surface from base44-dev/apper#11608 + base44/cli#547) — using your own coding agent, with no local checkout. The implementation is remote: writing a backend-function file into the sandbox is what ships it (the platform builds/deploys from there on a ~5s auto-commit).

New skills

  • base44-sandbox (hand-authored) — what you can author in the sandbox and how:
    • Supported: backend functions (base44/functions/), frontend code (src/…, SDK via base44-sdk), and OAuth connectors (set up via the connect flow, not by writing files).
    • Not supported yet: entities, agents.
    • No project-level CLI / deploy commands — writing the file is the deploy; run_command is only for build/type/lint checks and preview.
    • Concise inline backend-function guidance with a pointer to base44-cli's functions-create.md for depth — no duplicated reference copies.
  • base44-remote-dev — vendored connection skill (MCP endpoint + HTTP bridge, the read/write/edit/run tools, edit→preview→verify loop, persistence, concurrency), extended with a Connectors section documenting the list_connectors / initiate_connector_connection MCP tools.

Connectors (remote, no local filesystem)

Documented on both surfaces, with the two easy-to-miss semantics:

  • Declarative/replace scopes — connecting sets the connector to exactly the scopes passed (omitted scopes are removed); read current scopes first and pass the complete set.
  • Human consent — both surfaces return an authorization URL the user must open; then re-list to read the granted scopes.
Surface How
MCP list_connectors (apps:read) → initiate_connector_connection (apps:write, not sandbox:write)
CLI (projectless) base44 connectors list-availableinitiate --integration-type <t> --scopes <s...> --app-id <id>pull (resolves app id from --app-id/BASE44_APP_ID/.app.jsonc; no config.jsonc)

Packaging — installable as a subset on top of base44@base44-skills

A second base44-sandbox plugin bundling base44-remote-dev, base44-sandbox, base44-sdk, base44-troubleshooter — and excluding the deploy-oriented base44-cli.

  • Claude: claude plugin install base44-sandbox@base44-skills
  • Codex: codex plugin marketplace add base44/skills/pluginsBase44 Sandbox
  • skills CLI: npx skills add base44/skills --skill base44-remote-dev --skill base44-sandbox --skill base44-sdk --skill base44-troubleshooter

Implemented via a second entry in both marketplaces (.claude-plugin/marketplace.json, .agents/plugins/marketplace.json) and a plugins/base44-sandbox/ bundle with its own .claude-plugin / .codex-plugin / .cursor-plugin manifests + skills/assets symlinks (mirroring plugins/base44/).

Docs fix: function entry file is entry.ts

Corrected the backend-function examples to use entry.ts (and the function.jsonc "entry" value), not index.ts, across base44-sandbox, base44-sdk, and base44-cli docs. This matches the CLI's zero-config convention (ENTRY_FILE_GLOB = "**/entry.{js,ts}").

Fully contained in this (skills) repo — no CLI-repo change required. These examples are hand-authored in the skills repo, not extracted from CLI source by sync-cli-skill (which mirrors commander.js command definitions, not the conceptual function/automation docs). The CLI is already self-consistent: entry.ts is the documented convention, and the only index.ts-as-entry occurrences upstream are intentional config-based test fixtures. So nothing here will be reverted by a future sync.

Invocation was already correct everywhere (base44.functions.invoke('name', data)); no change needed.

Supporting changes

  • scripts/validate-template.mjs now discovers and validates all .cursor-plugin/plugin.json manifests (repo root + plugins/*/).
  • sync-cli-skill flags base44-sandbox for manual review when backend-function authoring conventions change (no auto byte-copy coupling).
  • README: new "Sandbox flavor" install section + skill-table rows.

Verification

  • node scripts/validate-template.mjs passes; all touched JSON parses.
  • Bundle symlinks committed as mode 120000.
  • base44-cli left structurally untouched (still auto-synced); only the hand-authored example filename corrected.

Open items to confirm against the real tools

  1. Codex multi-plugin — that two plugins[] entries render as two selectable items in /plugins.
  2. npx skills --skill repeatability — README documents repeated --skill; if unsupported, fall back to one invocation per skill.
  3. Cursor multi-manifest discovery — whether Cursor installs a subdir .cursor-plugin as a distinct plugin; if not, the Cursor path falls back to npx skills --skill.

🤖 Generated with Claude Code

@claude

claude Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

README check ran. 1 issue found: the base44-sandbox skill description said "no CLI" but the SKILL.md now documents OAuth connectors being configured via the projectless base44 connectors CLI. The fix was committed locally but git push failed — the remote branch has newer commits that need to be pulled first. Please pull and re-push, or run the workflow again.

carmelc added a commit to base44/cli that referenced this pull request Jun 18, 2026
Align the backend-function test fixtures and specs with the canonical
entry.ts convention (matching base44/skills#121): rename the config-based
fixtures' index.ts entry files to entry.ts, update their function.jsonc
"entry" fields, and update all specs that referenced index.ts as a function
entry/path (project, function-config, function-schema, functions deploy/
list/pull, logs).

The CLI's own docs (docs/resources.md) and source already use entry.ts; this
removes the stale index.ts examples from fixtures. Config-based discovery
still supports an arbitrary entry filename — when we document/support that
explicitly we'll add a dedicated index.ts example + test back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
carmelc and others added 8 commits June 18, 2026 15:08
Add a focused, separately-installable "sandbox flavor" for developing a
Base44 app inside Base44's cloud sandbox (PR base44-dev/apper#11608), where
the implementation is remote and writing a backend-function file is what
ships it — no local checkout and no Base44 CLI.

- skills/base44-sandbox: new hand-authored skill. Backend functions and
  frontend code are supported; entities, connectors, and agents are marked
  not-supported-yet; no automations. Concise inline guidance with a pointer
  to base44-cli's functions-create reference (no duplicated copies).
- skills/base44-remote-dev: vendored connection skill (MCP / HTTP bridge,
  tools, edit→preview→verify loop) from the upstream PR.
- New base44-sandbox plugin across channels: second entry in the Claude and
  Codex marketplaces + plugins/base44-sandbox/ bundle (its own .claude/.codex/
  .cursor manifests + skills/assets symlinks). Bundles base44-remote-dev,
  base44-sandbox, base44-sdk, base44-troubleshooter; excludes deploy-oriented
  base44-cli. npx skills --skill documented in the README.
- validate-template.mjs now discovers and validates all .cursor-plugin
  manifests (repo root + plugins/*/).
- sync-cli-skill flags base44-sandbox for manual review when function
  authoring conventions change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s CLI

Connectors are now usable in remote-dev (apper#11608 MCP connector tools +
cli#547 projectless connectors), so flip them from "not supported" to a
documented connect flow:

- list_connectors (apps:read) / initiate_connector_connection (apps:write)
  over MCP, and base44 connectors list-available/initiate/pull over the CLI
  with --app-id (no local project / config.jsonc).
- Document the declarative/replace scope semantics (read current scopes first,
  pass the complete set) and the human-consent authorization-URL step.
- Note the connector CLI is the one allowed CLI use in remote-dev; it targets
  a remote app by id with no deploy step (not a contradiction of the no-CLI
  rule, which is about local-project/deploy commands).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Upstream's base44-remote-dev SKILL.md doesn't yet list the connector tools
shipped in apper#11608, so add a "Connectors (OAuth integrations)" section
covering list_connectors (apps:read) and initiate_connector_connection
(apps:write) — declarative/replace scope semantics and the human-consent
redirect-URL step — plus the projectless base44 connectors CLI equivalent.

Marked as a local addition (HTML comment) to reconcile when upstream
documents these tools.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion

The connectors section will align with upstream by merge time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The function entry file (and the function.jsonc "entry" value) is entry.ts,
not index.ts. Update all function examples across base44-sandbox, base44-sdk,
and base44-cli docs (functions-create, automations, project-structure trees).

Invocation already uses base44.functions.invoke('name', data) everywhere; no
change needed there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ce-first

- Add "Using a connected connector in code": fetch the OAuth token via
  base44.asServiceRole.connectors.getConnection(type) inside a backend
  function, with a link to base44-sdk's connectors reference.
- Add a "Reference order & the complete README" section: prefer this skill
  and its siblings over web search, and point to the public app-specific
  onboarding README endpoint.
- Surface the reference-first note near the top too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sponse

invoke() resolves to the raw axios response, so the function's JSON is on
.data (not the top-level object), and it throws on non-2xx with the error
body at err.response.data. Update the invoke method doc and every frontend
example to read res.data, and add the warning in SKILL.md + QUICK_REFERENCE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a small frontend-calling clarification so agents read the function's
JSON off res.data and handle the non-2xx throw; link to base44-sdk for detail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@carmelc
carmelc force-pushed the feat/base44-sandbox-flavor branch from b2c30c9 to e979071 Compare June 18, 2026 12:10
carmelc and others added 7 commits June 21, 2026 11:14
Entities and agents are now authorable in the sandbox — writing the .jsonc
file auto-syncs, no entities/agents push or deploy. Flip both from
"not supported" to supported, broaden the mental model to "writing a resource
file is the deploy", and add Entities and Agents authoring sections (file
naming, schema, links to base44-cli references with their push/deploy
sections flagged as not applicable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the functions/entities pattern: link the Agents section to the
base44-cli Agent Schema and make clear to ignore agents push/pull/deploy
commands (sandbox auto-syncs the file).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…names

Remove the HTTP REST sandbox-bridge option (POST /api/apps/<id>/sandbox-bridge/<tool>)
from base44-remote-dev and base44-sandbox; local agents use MCP or the
`base44 sandbox` CLI instead.

Clarify CLI naming throughout: add the MCP-tool -> CLI-command mapping
(list_directory->sandbox ls, read_file->sandbox read, write_file->sandbox write,
edit_file->sandbox edit, run_command->sandbox run; grep/release unchanged) and
annotate inline tool references with their CLI command names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01842h6eP9hLWHnoRrERmbLo
The release command is no longer supported, so remove it from the
base44 sandbox CLI mapping table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01842h6eP9hLWHnoRrERmbLo
Add the `base44 sandbox checkpoint` CLI command (base44/cli#547) and the
`create_checkpoint` MCP tool (base44-dev/apper#11608) to the base44-remote-dev
and base44-sandbox skills, including the sandbox:write scope, the CLI/MCP name
mapping, and the COMMIT_FLUSH_PENDING error code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In the sandbox the function is inferred from the directory, so authors only
create entry.ts under base44/functions/<name>/; the function.jsonc config is
not required and is ignored in this mode.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
carmelc added a commit to base44/cli that referenced this pull request Jun 28, 2026
* feat(cli): sandbox + projectless connectors remote-dev commands

Rebased onto main and aligned with the projectless app-id mechanism added
in #541: --app-id is a global program option (bound to BASE44_APP_ID), and
requireAppContext commands resolve it through the lifecycle
(ensureAppContext -> initAppContext), so commands no longer need a bespoke
resolver. Dropped the parallel cli/utils/app-id.ts and the per-command
--app-id options from the earlier iteration.

Sandbox (new `base44 sandbox <tool>`, wraps apper #11608 sandbox-bridge):
- getSandboxClient(appId) + core/resources/sandbox {schema,api}
- list-directory/read-file/write-file/edit-file/grep/run-command/release,
  JSON-first stdout; write/edit payloads via flag or stdin (verbatim)
- commands use the default app-context lifecycle and read getAppContext().id

Connectors:
- new `connectors initiate --integration-type <type> [--scopes <s...>]`:
  initializes the connector and starts its OAuth flow; prints the URL
  (agent/non-interactive friendly), opens browser + polls when interactive
- pull/push work projectless: when the app context has no projectRoot
  (explicit --app-id/BASE44_APP_ID) they use ./connectors (--dir override);
  otherwise the linked project's connectors dir
- list-available already works projectless via the lifecycle (unchanged)

Tests: sandbox.spec.ts (9), connectors_initiate.spec.ts (6), projectless
cases for connectors pull/list-available. README updated. typecheck/lint/
knip clean. Pre-existing dev/exec spec failures are environment-dependent
(deno/network) and reproduce on clean main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(cli): normalize function fixtures to entry.ts

Align the backend-function test fixtures and specs with the canonical
entry.ts convention (matching base44/skills#121): rename the config-based
fixtures' index.ts entry files to entry.ts, update their function.jsonc
"entry" fields, and update all specs that referenced index.ts as a function
entry/path (project, function-config, function-schema, functions deploy/
list/pull, logs).

The CLI's own docs (docs/resources.md) and source already use entry.ts; this
removes the stale index.ts examples from fixtures. Config-based discovery
still supports an arbitrary entry filename — when we document/support that
explicitly we'll add a dedicated index.ts example + test back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): request sandbox:write scope in device login

The sandbox-bridge mutating tools (write/edit/run-command) require the
sandbox:write OAuth scope, which is deliberately kept out of the backend's
DEFAULT_SCOPE so shell access is never granted silently. Request it
explicitly in the device-code flow alongside apps:read/apps:write so
`base44 sandbox ...` works after login.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): hint to re-login when sandbox returns 403

A token issued before sandbox support (or without the sandbox:write scope)
gets a 403 from the sandbox-bridge endpoints. Augment forbidden responses
from sandbox commands with a hint to run 'base44 login' again to grant
sandbox access, while preserving the server's original error/hints.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): only hint re-login on a genuine missing-sandbox-scope error

The previous blanket 403 hint was wrong: the HTTP sandbox-bridge endpoints
the CLI calls authorize via the platform JWT + app-admin and do NOT enforce
sandbox:write (that check is MCP-only). Their 403s — feature-flag-off,
blocked app, view-only, wrong app type — are generic and not fixed by
re-login.

Detect the scope rejection specifically by matching the response wording
("sandbox:write" / "granting sandbox access", as emitted by the scope check)
instead of any 403, so the re-login hint only appears when it would actually
help. Added a test asserting a generic 403 (view-only) does NOT get the hint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): add global --json flag for machine-readable output

Add `--json` as a global program option (like --app-id) instead of a
per-command flag. The lifecycle centralizes the behavior:

- index.ts forces non-interactive wiring when --json is present, so the
  clack spinner and logs go to stderr.
- CLIContext gains `jsonMode`; Base44Command skips the clack framing and
  routes the status line to stderr, keeping stdout a pure JSON document.

Any command that sets RunCommandResult.stdout now yields clean JSON under
--json. Wired structured JSON output into the connectors commands
(list-available, initiate, pull, push); the sandbox commands already emit
JSON and now produce it pure. Pre-existing `logs --json` benefits too.

Tests: pure-JSON stdout assertions for sandbox + connectors list-available
+ initiate. typecheck/lint/knip clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): generic --json fallback for commands without native JSON

Make --json a universal contract in Base44Command so every command emits
valid JSON on stdout, even ones that don't build a machine payload:

- success: a command that sets result.stdout gets it verbatim (native JSON,
  status to stderr); otherwise the human status line is wrapped as
  { "output": "<text>" } (ANSI stripped).
- failure: any command emits a JSON error envelope on stdout —
  { "error", "code"?, "details"?, "hints"? } from the CLIError fields.

So `base44 whoami --json` -> {"output":"Logged in as: ..."} and a failing
`base44 sandbox list-directory --json` (no app id) -> {"error":"No Base44
app ID found.","code":"...","hints":[...]} instead of empty stdout.

Native/structured output (sandbox, connectors) is kept — it's richer than
the wrapped-status fallback (e.g. initiate still exposes redirectUrl /
connectionId as fields).

Tests: whoami --json (fallback wrap) and sandbox --json error envelope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: document the global --json flag (machine output + silent mode)

- README: add a "Global flags" section covering --app-id and --json, with
  the contract (pure JSON stdout, silent mode, JSON error envelope,
  universal) and sandbox/jq examples.
- AGENTS.md/CLAUDE.md: note that --json forces silent mode in the
  @clack/prompts rule, and add a rule so new commands keep stdout
  machine-parseable (return RunCommandResult.stdout, status via
  outroMessage/log, emit JSON when ctx.jsonMode).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(cli): shorten sandbox subcommand names

The sandbox namespace already supplies the file/shell context, so the
redundant nouns on each subcommand can be dropped to match the CLI's
one-word-where-possible naming convention:

  list-directory -> ls
  read-file      -> read
  write-file     -> write
  edit-file      -> edit
  run-command    -> run

grep and release are already concise and unchanged. The scope itself
stays `sandbox` to keep the CLI aligned with the platform vocabulary
(the sandbox:write OAuth scope, backend, and error hints).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ew3Z6LjEgToj2bZyQHMQb

* refactor(cli): remove the sandbox release command

The sandbox release command is no longer needed. Removes the command,
its API client function, response schema, test, and README entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5MJy3X1QEiXo2NFTD5Hpx

* feat(cli): add sandbox checkpoint command

Adds `base44 sandbox checkpoint` to create a restore-point checkpoint of
an app's remote sandbox via the create_checkpoint sandbox-bridge tool.
Takes an optional --name (message/title; defaults to an auto-generated
title) and returns the checkpoint id, name, and git commit hash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5MJy3X1QEiXo2NFTD5Hpx

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@carmelc
carmelc merged commit 1463369 into main Jun 30, 2026
2 checks passed
@carmelc
carmelc deleted the feat/base44-sandbox-flavor branch June 30, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants